// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu

/// example:
/// bazel build //cc/appcoin2/support/feed:plot
/// ./bazel-bin/cc/appcoin2/support/feed/plot --driver ./data/coin2/feed/examples/...json

#include <boost/algorithm/string.hpp>
#include <cxxopts.hpp>

#include "coin2/app/driver.h"
#include "coin2/base/config/app_config.h"
#include "coin2/base/config/args.h"
#include "coin2/exchange/feed.pb.h"
#include "coin2/strategy/strategy.h"
#include "presto/quant/math/moving_average.h"
#include "vitro.h"  // NOLINT

using coin2::exchange::base::feed::FeedUpdate;
using namespace coin2::app;
using namespace coin2::base::config;
using coin2::base::window::TimeMovingWindow;

TimeMovingWindow window_15ms(15000000);
std::vector<double> data;
std::vector<double> intervals;

struct Strategy : public ::coin2::strategy::IStrategy {
  void onTradeFeed(const FeedUpdate& upd) override {
    auto ts = upd.timestamp();
    window_15ms.Push(ts, 1.0);
    data.push_back(window_15ms.size());
    if (last > 0) {
      intervals.push_back(ts - last);
    }
    last = ts;
  }
  int64_t last = 0;
};

using coin2::app::DriverConfig;

DriverConfig parse_cli(int argc, char* argv[]) {
  // you have 2 options to provide flags.
  // 1. --driver
  // 2. --machine --fastfeed --...
  // mixing these 2 is discouraged.

  DriverConfig app;
  cxxopts::Options opt("Feed Plot", "Plot feed");
  AddDriverOptions(&opt);                                         // --driver
  AddIntervalOptions(&opt);                                       // --start --end --duration
  opt.add_options()                                               // add options
      ("machine", "feed machine", cxxopts::value<std::string>())  //
      ("mea", "M.E.A", cxxopts::value<std::string>())             //
      ("recipe", "recipe", cxxopts::value<std::string>())         //
      ("product", "a norm symbol", cxxopts::value<std::vector<std::string>>());  //

  auto res = opt.parse(argc, argv);

  if (!ParseDriverOptions(res, &app)) {
    auto& exchanges = *app.mutable_feed()->mutable_exchanges();
    auto& exchange = exchanges[res["mea"].as<std::string>()];

    exchange.set_mea(res["mea"].as<std::string>());
    exchange.set_recipe(res["recipe"].as<std::string>());
    exchange.set_type(coin2::exchange::feed::FeedSystemType::FEED_SYSTEM_TYPE_ARCHIVE);
    for (const auto& norm : res["product"].as<std::vector<std::string>>()) {
      exchange.mutable_products()->add_norms(norm);
    }

    exchange.mutable_archive()->set_archive_type(coin2::exchange::feed::ArchiveConfig::FASTFEED);
    exchange.mutable_archive()->set_machine(res["machine"].as<std::string>());
  }
  ParseIntervalOptions(
      res,
      app.mutable_feed()->mutable_common()->mutable_archive()->mutable_interval());

  return app;
}

int main(int argc, char* argv[]) {
  /* ----------------------------------- opt ---------------------------------- */
  coin2::app::DriverConfig app = parse_cli(argc, argv);

  /* ----------------------------------- run ---------------------------------- */
  printf("reading ..\n");

  Strategy strategy;
  ::coin2::app::Driver driver(app, &strategy);
  driver.Run();

  /* ---------------------------------- dump ---------------------------------- */

  Figure fig(2, 1);
  fig.title = "Trade Burst";
  fig.width = 1600;
  fig.height = 1200;
  fig.height_ratios = {0.5, 0.5};

  /* ---------------------------- plot - 15ms bin histogram (trade) ----------- */
  {
    auto& ax = fig.axes(1, 1);
    ax.title = "# of Trade in 15ms";
    ax.xlabel = "# of Trades in 15ms";
    ax.ylabel = "Occurences";
    ax.legend = "upper left";
    ax.xlim_left = 0;
    ax.xlim_right = +100;
    // ax.xtick_major = "multiple";
    // ax.xtick_major_multiple = 100;
    ax.grid = true;

    auto& hist = ax.histogram({"15ms count"}, 100, {data});
    hist.cumulative = 1;
    hist.alpha = 1.0;
  }
  {
    auto& ax = fig.axes(2, 1);
    ax.title = "Trade Intervals";
    ax.ylabel = "Occurences";
    ax.legend = "upper left";
    ax.xlim_left = 0;
    ax.xlim_right = 1e9;
    ax.grid = true;
    ax.xscale = "log";

    auto& hist = ax.histogram({"trade interval"}, 1000, {intervals});
    hist.cumulative = 1;
    hist.alpha = 1.0;
    hist.bin_log_scale = true;
  }

  Matplot matplot(fig);
  matplot.save("trade-burst.png");

  return 0;
}
